﻿using JGSY.SerialCommunication.UpperComputer.Component;
using JGSY.SerialCommunication.UpperComputer.Core;
using JGSY.SerialCommunication.UpperComputer.Core.EnumType;
using JGSY.SerialCommunication.UpperComputer.IComponent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace JGSY.SerialCommunication.UpperComputer.Modbus
{
    public class ModbusUDP : ModbusBase
    {
        public override bool IsModbusTcp { get { return false; } }
        public override bool IsIgnoreMABP { get; set; } = false;
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="ipAddress">地址</param>
        /// <param name="port">端口默认502</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="isIgnore">UDP忽略MABP</param>
        public ModbusUDP(string ipAddress, int port = 502, int timeout = 1000, bool isIgnore = false)
        {
            IsIgnoreMABP = isIgnore;
            CommunicationUnit = new Ethernet(ipAddress, port, timeout, timeout, ProtocolType.Udp);
        }

        //protected override async Task<byte[]> SendRequestAsync(List<byte> pdu)
        public override byte[] SendRequest(List<byte> pdu)
        {
            if (pdu == null || pdu.Count == 0)
                throw new ArgumentNullException(nameof(pdu), "PDU不能为空");

            Result<bool> connectState = ((Ethernet)CommunicationUnit).OpenAsync(1000).Result;

            if (!connectState.Status)
            {
                return new byte[0];
            }

            if (IsIgnoreMABP)
            {
                return SendRequestIgnoreMabp(pdu);
            }

            //List<byte> bytesMBAP = new List<byte>();
            //// 构建完整的Modbus UDP消息 (MBAP + PDU)
            //byte[] transactionId = BitConverter.GetBytes((ushort)System.Threading.Interlocked.Increment(ref TransactionId));
            //if (BitConverter.IsLittleEndian)
            //    Array.Reverse(transactionId);
            //bytesMBAP.AddRange(transactionId);
            //byte[] protocolId = new byte[] { 0x00, 0x00 }; // Modbus协议ID
            //bytesMBAP.AddRange(protocolId);
            //byte[] length = BitConverter.GetBytes((ushort)(pdu.Count + 1));
            //if (BitConverter.IsLittleEndian)
            //    Array.Reverse(length);
            //bytesMBAP.AddRange(length);
            // 构建完整的Modbus UDP消息 (MBAP + PDU)
            byte[] transactionId = BitConverter.GetBytes((ushort)System.Threading.Interlocked.Increment(ref TransactionId));
            if (BitConverter.IsLittleEndian)
                Array.Reverse(transactionId);
            byte[] protocolId = new byte[] { 0x00, 0x00 }; // Modbus协议ID
            byte[] length = BitConverter.GetBytes((ushort)(pdu.Count));
            if (BitConverter.IsLittleEndian)
                Array.Reverse(length);
            int baseIndex = 7;
            //byte unitId = 0x01; // 通常为1  和Rtu ASCII的从站地址一样  ，已经添加了这里就除去了 否则重复
            baseIndex -= 1;
            byte[] request = new byte[baseIndex + pdu.Count];
            Array.Copy(transactionId, 0, request, 0, 2);
            Array.Copy(protocolId, 0, request, 2, 2);
            Array.Copy(length, 0, request, 4, 2);
            //request[6] = unitId;
            Array.Copy(pdu.ToArray(), 0, request, baseIndex, pdu.Count);

            var repContent = ModbusLengthCalculator.ExtractDataFromRequest(ModbusProtocolType.UdpIp, request.ToArray(), IsIgnoreMABP);
            int functionCode = repContent.FunctionCode;
            int dataCount = repContent.DataCount;
            int receiveLen = ModbusLengthCalculator.CalculateNormalResponseLength(ModbusProtocolType.UdpIp, functionCode, dataCount);

            int errrorLen = ModbusLengthCalculator.CalculateExceptionResponseLength(ModbusProtocolType.UdpIp);


            // 使用通信单元发送请求并接收响应
            var result = ((Ethernet)CommunicationUnit).SendAndReceiveAsync(
                request.ToList(),
                receiveLen,
                errrorLen).Result; // 异常响应长度为9字节(MBAP+异常信息)

            if (!result.Status)
                throw new InvalidOperationException($"通信失败: {result.Message}");

            List<byte> responseBuffer = result.Datas;

            if (responseBuffer.Count < 9) // 至少需要MBAP(6) + 单元ID(1) + 功能码(1) + 至少1字节数据
                throw new InvalidDataException("接收到的响应长度不足");

            // 验证事务标识符
            byte[] receivedTransactionId = new byte[2];
            Array.Copy(responseBuffer.ToArray(), 0, receivedTransactionId, 0, 2);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(receivedTransactionId);

            if (BitConverter.ToUInt16(receivedTransactionId, 0) != TransactionId)
                throw new InvalidDataException("事务标识符不匹配");

            // 提取PDU部分 (跳过MBAP头)
            byte[] responsePdu = new byte[responseBuffer.Count - 6];
            Array.Copy(responseBuffer.ToArray(), 6, responsePdu, 0, responseBuffer.Count - 6);

            return responsePdu;


        }

        public  byte[] SendRequestIgnoreMabp(List<byte> pdu)
        {
            if (pdu == null || pdu.Count == 0)
                throw new ArgumentNullException(nameof(pdu), "PDU不能为空");

            Result<bool> connectState = ((Ethernet)CommunicationUnit).OpenAsync(1000).Result;

            if (!connectState.Status)
            {
                return new byte[0];
            }
            
            // 构建完整的Modbus UDP消息 ( PDU) UDP忽略MBAP
            var repContent = ModbusLengthCalculator.ExtractDataFromRequest(ModbusProtocolType.UdpIp, pdu.ToArray(), IsIgnoreMABP);
            int functionCode = repContent.FunctionCode;
            int dataCount = repContent.DataCount;
            int receiveLen = ModbusLengthCalculator.CalculateNormalResponseLength(ModbusProtocolType.UdpIp, functionCode, dataCount);
            int errrorLen = ModbusLengthCalculator.CalculateExceptionResponseLength(ModbusProtocolType.UdpIp);

            // 使用通信单元发送请求并接收响应
            var result = ((Ethernet)CommunicationUnit).SendAndReceiveAsync(
                pdu.ToList(),
                receiveLen,
                errrorLen).Result; // 异常响应长度为9字节(MBAP+异常信息)

            if (!result.Status)
                throw new InvalidOperationException($"通信失败: {result.Message}");

            List<byte> responseBuffer = result.Datas;

            if (responseBuffer.Count < 9-6) // 至少需要MBAP(6) + 单元ID(1) + 功能码(1) + 至少1字节数据
                throw new InvalidDataException("接收到的响应长度不足");

            //// 验证事务标识符
            //byte[] receivedTransactionId = new byte[2];
            //Array.Copy(responseBuffer.ToArray(), 0, receivedTransactionId, 0, 2);
            //if (BitConverter.IsLittleEndian)
            //    Array.Reverse(receivedTransactionId);

            //if (BitConverter.ToUInt16(receivedTransactionId, 0) != TransactionId)
            //    throw new InvalidDataException("事务标识符不匹配");

            // 提取PDU部分 (跳过MBAP头)
            byte[] responsePdu = new byte[responseBuffer.Count - 6];
            Array.Copy(responseBuffer.ToArray(), 6, responsePdu, 0, responseBuffer.Count - 6);

            return responsePdu;

        }
    }

}